/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.taskrunner
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	/**
	 * Gets tasks from a TaskFactory and executes them, temporarily caching the result until it is 
	 * retrieved, supporting multiple asynchronous task execution.
	 */
	public class TaskRunner extends EventDispatcher
	{
		protected var completedTasks:Dictionary;
		
		protected var _taskFactory:ITaskFactory;
		public function get taskFactory():ITaskFactory
		{
			return _taskFactory;
		}
		public function set taskFactory(value:ITaskFactory):void
		{
			_taskFactory = value;
		}
		
		
		/**
		 * Constructor.
		 */
		public function TaskRunner(taskFactory:ITaskFactory = null)
		{
			completedTasks = new Dictionary();
			_taskFactory = taskFactory;
		}
		
		
		/**
		 * Get the result, delete the entry from completedTasks dictionary, return the result.
		 */
		public function result(id:String):*
		{
			var result:* = completedTasks[id];
			delete completedTasks[id];
			return result;
		}
		
		
		/**
		 * Execute task if new, dispatch TaskEvent.TASK_COMPLETE if cached. 
		 */
		public function addTask(request:IRequest):void
		{
			if(completedTasks[request.id] == null)
			{
				startTask(request);
			}
			else
			{
				dispatchEvent(new TaskEvent(TaskEvent.TASK_COMPLETE, request.id));
			}
		}
		
		
		/**
		 * Convert a Request to Task and execute.
		 */
		protected function startTask(request:IRequest):void
		{
			var task:ITask = _taskFactory.getTask(request);
			task.addEventListener(TaskEvent.TASK_COMPLETE, task_completeHandler);
			task.addEventListener(TaskEvent.TASK_FAILURE, task_errorHandler);
			task.run();
		}
		
		
		/**
		 * Task complete, add result to cache, unhook, dispatch TaskEvent.TASK_COMPLETE
		 */
		protected function task_completeHandler(event:Event):void
		{
			var task:ITask = ITask(event.target);
			task.removeEventListener(TaskEvent.TASK_COMPLETE, task_completeHandler);
			task.removeEventListener(TaskEvent.TASK_FAILURE, task_errorHandler);

			completedTasks[task.id] = task.result; /* store the result for external reference */

			dispatchEvent(new TaskEvent(TaskEvent.TASK_COMPLETE, task.id));
		}
		
		
		/**
		 * Task error, unhook, dispatch TaskEvent.TASK_FAILURE
		 */
		protected function task_errorHandler(event:TaskEvent):void
		{
			var task:ITask = ITask(event.target);
			task.removeEventListener(TaskEvent.TASK_COMPLETE, task_completeHandler);
			task.removeEventListener(TaskEvent.TASK_FAILURE, task_errorHandler);

			dispatchEvent(new TaskEvent(TaskEvent.TASK_FAILURE, task.id));
		}
	}
}